package com.leyou.item.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.constant.MQConstants;
import com.leyou.common.dto.PageResult;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.entity.Category;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 事务的传播行为值如果为：(propagation = Propagation.REQUIRED)
 * 如果当前方法没有事务，就开启一个新的事务，如果有，就假如当前之前的事务。
 * 始终保证当前方法有且只有一个事务。
 */
@Service
@Transactional
public class GoodsService {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper detailMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<SpuDTO> spuPageQuery(Integer page, Integer rows, String key, Boolean saleable) {
        //设置分页参数
        PageHelper.startPage(page, rows);
        //封装复杂查询对象
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();
        //判断是否有搜索条件
        if(!StringUtils.isEmpty(key)){
            criteria.andLike("name", "%"+key+"%");
        }
        //判断是否有上下架要求
        //说明：mysql中tinyint就是布尔值，0为false,非0为true。
        //java中只要给tinyint传true，则数据库自动保存为1，否则保存为0。
        if(saleable!=null){
            criteria.andEqualTo("saleable", saleable);
        }
        //mybatis查询
        List<Spu> spus = spuMapper.selectByExample(example);
        //判空
        if(CollectionUtils.isEmpty(spus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //得到pageHelper的分页对象
        PageInfo<Spu> pageInfo = new PageInfo<>(spus);
        //将Spu集合转成SpuDTO集合
        List<SpuDTO> spuDTOS = BeanHelper.copyWithCollection(pageInfo.getList(), SpuDTO.class);
        //给SpuDTO集合中每个对象的分类名称和品牌名称赋值
        handlerCategoryNameAndBrandName(spuDTOS);
        //得到自定义的分页对象
        PageResult<SpuDTO> pageResult = new PageResult<>(pageInfo.getTotal(),
                pageInfo.getPages(),
                spuDTOS);
        return pageResult;
    }

    //给SpuDTO集合中每个对象的分类名称和品牌名称赋值
    private void handlerCategoryNameAndBrandName(List<SpuDTO> spuDTOS) {
        //遍历
        spuDTOS.forEach(spuDTO -> {
            //根据品牌id查询品牌对象并进一步获取品牌名称
            String brandName = brandService.findBrandById(spuDTO.getBrandId()).getName();
            spuDTO.setBrandName(brandName);

            //根据分类id的集合查询出分类对象的集合并进一步收集到全部分类名称用|拼接
            String categoriesNames = categoryService.findCategoriesByIds(spuDTO.getCategoryIds())//获取到分类对象的集合List<Category>
                    .stream()//list集合转流
                    .map(Category::getName)//收集到List<Category>中所有Category的name值
                    .collect(Collectors.joining("|"));//将收集到的所有Category的name值用|拼接
            spuDTO.setCategoryName(categoriesNames);
        });
    }

    public void saveGoods(SpuDTO spuDTO) {
        try {
            //将SpuDTO转成Spu
            Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);
            //将商品状态置为下架
            spu.setSaleable(false);
            //保存Spu
            spuMapper.insertSelective(spu);

            //得到SpuDetail对象
            SpuDetail spuDetail = spuDTO.getSpuDetail();
            spuDetail.setSpuId(spu.getId());
            //保存SpuDetail对象
            detailMapper.insertSelective(spuDetail);

            //得到Sku集合
            List<Sku> skus = spuDTO.getSkus();
            //给每个Sku对象的SpuId赋值
            skus.forEach(sku -> {
                sku.setSpuId(spu.getId());
                sku.setCreateTime(new Date());
                sku.setUpdateTime(new Date());
            });
            //批量保存
            skuMapper.insertList(skus);

        }catch (Exception e){
            e.printStackTrace();
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    /**
     * 上下架
     */
    public void updateSaleable(Long id, Boolean saleable) {
        try {
            Spu record = new Spu();
            record.setId(id);
            record.setSaleable(saleable);
            spuMapper.updateByPrimaryKeySelective(record);

            //同步维护索引库和静态化页面，就是在修改完上下架状态后通过feign去操作search服务和page服务
            //一旦search服务和page服务中有操作失败，则上下架操作也失败。
            //很明显我们不想让上下架业务受制于search服务和page服务，所以我们采用MQ异步方式来解决此问题。
            //指定routingKey
            String routingKey = saleable ? MQConstants.RoutingKey.ITEM_UP_KEY : MQConstants.RoutingKey.ITEM_DOWN_KEY;
            //参数一：交换机，参数二：routingkey，参数三：发送的内容
            amqpTemplate.convertAndSend(MQConstants.Exchange.ITEM_EXCHANGE_NAME, routingKey, id);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
    }

    public SpuDetail findSpuDetailBySpuId(Long id) {
        SpuDetail spuDetail = detailMapper.selectByPrimaryKey(id);
        if(spuDetail==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return spuDetail;
    }

    public List<Sku> findSkusBySpuId(Long id) {
        Sku record = new Sku();
        record.setSpuId(id);
        List<Sku> skus = skuMapper.select(record);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public SpuDTO findSpuDTOBySpuId(Long id) {
        //查询Spu对象
        Spu spu = spuMapper.selectByPrimaryKey(id);
        if(spu==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //将Spu转成SpuDTO对象
        SpuDTO spuDTO = BeanHelper.copyProperties(spu, SpuDTO.class);
        //给SpuDTO中SpuDetail对象赋值
        SpuDetail spuDetail = findSpuDetailBySpuId(id);
        spuDTO.setSpuDetail(spuDetail);
        //给SpuDTO中Sku集合赋值
        List<Sku> skus = findSkusBySpuId(id);
        spuDTO.setSkus(skus);
        return spuDTO;
    }

    public List<Sku> findSkusByIds(List<Long> ids) {
        List<Sku> skus = skuMapper.selectByIdList(ids);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public void minusStock(Map<Long, Integer> paramMap) {
        try {
            paramMap.entrySet().forEach(entry->{
                //获取skuId
                Long skuId = entry.getKey();
                //获取要减的数量
                Integer num = entry.getValue();
                //根据id查询sku
                Sku sku = skuMapper.selectByPrimaryKey(skuId);
                //封装条件
                Sku record = new Sku();
                record.setId(skuId);
                record.setStock(sku.getStock()-num);
                //修改操作
                skuMapper.updateByPrimaryKeySelective(record);
            });
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

    }

}
